using System;
using System.Collections.Generic;
using TTDotNet.Engine;

namespace TTDotNet.Util
{
    public struct Coordinate
    {
        private int x;
        private int z;
        private static Coordinate invalid;

        static Coordinate() 
        {
            invalid.X = -1;
            invalid.Z = -1;
        }

        public static Coordinate Invalid
        {
            get { return invalid; }
        }

        public bool IsInvalid
        {
            get { return (x == invalid.X || z == invalid.Z); }
        }

        public Coordinate(int xCoord, int zCoord)
        {
            this.x = xCoord;
            this.z = zCoord;
        }

        public int Get(Axis axis)
        {
            if (axis == Axis.X) { return x; }
            else { return z; }
        }

        public int X
        {
            get { return x; }
            set { x = value; }
        }

        public int Z
        {
            get { return z; }
            set { z = value; }
        }

        public Coordinate Clone()
        {
            return new Coordinate(x, z);
        }

        public int StraightLineDistanceTo(Coordinate coord)
        {
            if (x == coord.X)
            {
                return Math.Abs(z - coord.Z) + 1;
            }
            else if (z == coord.Z)
            {
                return Math.Abs(x - coord.X) + 1;
            }
            else { return -1; }
        }

        public int GridDistanceTo(Coordinate coord)
        {
            return Math.Abs(x - coord.X) + Math.Abs(z - coord.Z);
        }

        public bool AdjacentTo(Coordinate coord)
        {
            if (Math.Abs(coord.X - x) == 1 && z == coord.Z)
            {
                return true;
            }
            if (Math.Abs(coord.Z - z) == 1 && x == coord.X)
            {
                return true;
            }
            return false;
        }

        public bool IsBetween(Coordinate start, Coordinate finish)
        {
            bool xEqual = false;
            bool zEqual = false;

            if (start.X == finish.X) xEqual = true;
            if (start.Z == finish.Z) zEqual = true;

            if ((xEqual || zEqual) == false) return false;

            if (xEqual && zEqual && x == start.X && z == start.Z) return true;

            if (xEqual)
            {
                if (start.Z < finish.Z)
                {
                    if ((z >= start.Z && z <= finish.Z) && x == start.X) { return true; } else { return false; }
                }
                else
                {
                    if ((z <= start.Z && z >= finish.Z) && x == start.X) { return true; } else { return false; }
                }
            }
            else
            {
                if (start.X < finish.X)
                {
                    if ((x >= start.X && x <= finish.X) && z == start.Z) { return true; } else { return false; }
                }
                else
                {
                    if ((x <= start.X && x >= finish.X) && z == start.Z) { return true; } else { return false; }
                }
            }

        }


        public override string ToString()
        {
            return "(" + x + "," + z + ")";
        }


        public override bool Equals(object obj)
        {
            Coordinate coord = (Coordinate)obj;
            if (coord.X == this.x && coord.Z == this.z) return true;
            return false;
        }

        public bool Equals(int x, int z)
        {
            if (x == this.x && z == this.z) return true;
            return false;
        }

        //public override int GetHashCode()
        //{
        //    return Int32.Parse(x.ToString() + z.ToString());
        //}

        public static List<Coordinate> GetAdjacents(Coordinate coord)
        {
            List<Coordinate> adjacents = new List<Coordinate>();

            int x = coord.X;
            int z = coord.Z;

            if (z < Game.gameWorld.Length - 1)
                adjacents.Add(new Coordinate(x, z + 1));

            if (x < Game.gameWorld.Width - 1)
                adjacents.Add(new Coordinate(x + 1, z));

            if (z > 0)
                adjacents.Add(new Coordinate(x, z - 1));

            if (x > 0)
                adjacents.Add(new Coordinate(x - 1, z));

            return adjacents;
        }

        public static List<Coordinate> GetNeighbours(Coordinate coord)
        {
            List<Coordinate> neighbours = new List<Coordinate>();
            neighbours.AddRange(GetAdjacents(coord));

            int x = coord.X;
            int z = coord.Z;

            if(x < Game.gameWorld.Width -1 && z < Game.gameWorld.Length - 1)
                neighbours.Add(new Coordinate(x + 1, z + 1));

            if(x < Game.gameWorld.Width - 1 && z > 0) 
                neighbours.Add(new Coordinate(x + 1, z - 1));

            if(x > 0 && z > 0)
                neighbours.Add(new Coordinate(x - 1, z - 1));

            if(x > 0 && z < Game.gameWorld.Length - 1)
                neighbours.Add(new Coordinate(x - 1, z + 1));

            return neighbours;
        }
    }

    public class DDDCoordinate
    {
        private int x;
        private int y;
        private int z;
        private static DDDCoordinate invalid;

        static DDDCoordinate() 
        {
            invalid = new DDDCoordinate(-1, -1, -1);
        }

        public DDDCoordinate(int x, int y, int z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public DDDCoordinate(Coordinate coord, int y)
        {
            this.x = coord.X;
            this.y = y;
            this.z = coord.Z;
        }

        public bool IsInvalid
        {
            get { return (x == invalid.X || y == invalid.Y || z == invalid.Z); }
        }

        public override bool Equals(object obj)
        {
            DDDCoordinate temp = (DDDCoordinate)obj;
            return (temp.X == x && temp.Y == y && temp.Z == z);
        }

        public override int GetHashCode()
        {
            string s = (x + "," + y + "," + z);
            return s.GetHashCode();
        }

        public int X
        {
            get { return x; }
            set { x = value; }
        }

        public int Y
        {
            get { return y; }
            set { y = value; }
        }

        public int Z
        {
            get { return z; }
            set { z = value; }
        }

        public bool AdjacentTo(DDDCoordinate coord)
        {
            if (Math.Abs(coord.X - x) == 1 && z == coord.Z)
            {
                return true;
            }
            if (Math.Abs(coord.Z - z) == 1 && x == coord.X)
            {
                return true;
            }
            return false;
        }

        public int StraightLineDistanceTo(DDDCoordinate coord)
        {
            if (x == coord.X)
            {
                return Math.Abs(z - coord.Z) + 1;
            }
            else if (z == coord.Z)
            {
                return Math.Abs(x - coord.X) + 1;
            }
            else { return -1; }
        }

        public int GridDistanceTo(DDDCoordinate coord)
        {
            return Math.Abs(x - coord.X) + Math.Abs(z - coord.Z);
        }

        public override string ToString()
        {
            return "(" + x + "," + y + "," + z + ")";
        }

        
    }
}
